package com.hu.boot.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Configuration;

// 切面配置类
@Configuration // 代表这个类是一个 spring 配置类
@Aspect // 代表这个类是一个切面类
public class AspectConfig {

    /*
        通过 @Pointcut 声明一个公共的切入点表达式
            表达式支持 execution 表达式和 within 表达式以及基于注解的切入点表达式
            execution 是方法级别的的切入点表达式,运行效率较低
            within 是类级别的切入点表达式,运行效率较高
            注解的切入点表达式
                声明一个注解
                在需要添加通知的方法上添加这个注解

            当需要给一个类中的所有方法都添加切入点表达式时,建议使用 within
     */
//    @Pointcut("execution(* com.hu.boot.service.*.*(..))")
    @Pointcut("@annotation(com.hu.boot.annotation.AdviceAnnotation)")
    public void pointCut() {
    }

    // 前置通知,在目标对象方法执行之前执行
    @Before("pointCut()")
    public void before(JoinPoint joinPoint){
        System.out.println("=====前置通知=====");
        System.out.println("=====当前执行目标类 " + joinPoint.getTarget() + "=====");
        System.out.println("=====当前执行目标类中方法 " + joinPoint.getSignature().getName() + "=====");
    }

    // 后置通知,在目标对象方法的 finally 语句中执行(始终会执行)
    @After("pointCut()")
    public void after(JoinPoint joinPoint){
        System.out.println("=====后置通知=====");
        System.out.println("=====当前执行目标类 " + joinPoint.getTarget() + "=====");
        System.out.println("=====当前执行目标类中方法 " + joinPoint.getSignature().getName() + "=====");
    }

    @Around("pointCut()")
    public Object aroundAdviceMethod(ProceedingJoinPoint proceedingJoinPoint) {
        Object result = null;
        try {
            System.out.println("环绕通知 --> 前置通知");
            // 表示目标对象方法的执行, result 为目标对象方法执行之后的返回值
            result = proceedingJoinPoint.proceed();
            System.out.println("环绕通知 --> 返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知 --> 异常通知");
        } finally {
            System.out.println("环绕通知 --> 后置通知");
        }
        // 环绕通知的方法的返回值一定要和目标对象方法的返回值一致
        return result;
    }

}
